package org.ifdb.dao;

import java.lang.reflect.ParameterizedType;
import java.util.Iterator;
import java.util.List;

import javax.jdo.PersistenceManager;

import org.ifdb.persistency.PMF;

import com.google.appengine.api.datastore.Key;

/**
 * 
 * @author panthro.rafael@gmail.com
 * 
 * @param <T>
 *            the Type that this class will work on, <b>must be</b> a
 *            Persistence Capable class
 */
public abstract class AbstractDAO<T> {

    /**
     * Keeps the generic type used in it's subclass
     * 
     */
    protected Class<?>           type;

    /**
     * The {@link javax.jdo.PersistenceManager} that will be used to manage all
     * persistent objects in this class
     */
    protected PersistenceManager pm;

    /**
     * Class constructor that is always called
     */
    protected AbstractDAO() {
        type = (Class<?>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        pm = PMF.get().getPersistenceManager();
    }

    /**
     * Make the object persistent
     * 
     * @param object
     *            the instance of the generiv Type to be created
     * @return the same object but now persistence capable
     */
    public T create(T object) {
        return pm.makePersistent(object);
    }

    /**
     * Create the list of Objects
     * 
     * @param objects
     *            a {@link java.util.List} of the generic Type
     * @return the same {@link java.util.List} of the generic Type, but
     *         persistence capable
     */
    public List<T> createAll(List<T> objects) {
        return pm.makePersistent(objects);
    }

    /**
     * Deletes the instance from datastore
     * 
     * @param object
     *            the object instance to be deleted
     */
    public void delete(T object) {
        pm.deletePersistent(object);
    }

    /**
     * Delete the list of Objects
     * 
     * @param objects
     *            a {@link java.util.List} of the generic Type
     */
    public void deleteAll(List<T> objects) {
        pm.deletePersistentAll(objects);
    }

    /**
     * Finds all persistent instances of the Generic type
     * 
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<T> findAll() {
        return (List<T>) pm.newQuery(type).execute();
    }

    /**
     * Finds an instance of the Generic Type
     * 
     * @param key
     *            an instance of {@link Key} of an object (already persistent)
     *            of the generic Type
     * @return the Object of generic type or null if not found
     */
    @SuppressWarnings("unchecked")
    public T findByKey(Key key) {
        return (T) pm.getObjectById(type, key);
    }

    /**
     * Assistence method to iterate over all instances of the generic type <br/>
     * faster than calling <b>findAll().iterator()</b>
     * 
     * @return an {@link Iterator} instance of generic type
     */
    @SuppressWarnings("unchecked")
    public Iterator<T> getIterator() {
        return (Iterator<T>) pm.getExtent(type).iterator();
    }

}
